home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 10
/
The PC-Sig Library - Shareware for the IBM PC and Compatibles (PC-SIG)(Tenth Edition Disks 1-2804)(1991).iso
/
PC_SIGCD
/
05
/
6
/
DISK0564.ZIP
/
SOURCE.ARC
/
TAIL.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-07-09
|
14KB
|
493 lines
TITLE TAIL - A FILTER FOR MSDOS2
PAGE 55,132
;**********************************************************************
; THIS PROGRAM PRINTS THE LAST FEW LINES OF A TEXT FILE.
;
; USAGE: TAIL -n filename
; -n is optional, limits output to n lines (20 default)
;
; BY: JON DART
; 3012 HAWTHORN ST.,
; SAN DIEGO, CA 92104
;
; VERSION 1.8: 02-OCT-87 ASSEMBLES UNDER MASM 5.0
; VERSION 1.7: 10-JAN-87 HANDLES AMBIG. FILE NAMES, MULTIPLE FILES
; VERSION 1.6: 14-AUG-86 HANDLES -n UP TO 65535, NOW BUFFERS OUTPUT
; VERSION 1.5: 06-JUL-86 CHANGES TO MEMORY ALLOC, + NOW ASSEMBLES UNDER
; MASM 4.0
; VERSION 1.4: 04-FEB-86 FIXED BUG, NOW READS FROM STDIN CORRECTLY
; VERSION 1.3: 16-JAN-86 MORE KOSHER MEMORY USAGE, NOW .EXE FILE
; VERSION 1.2: 27-SEP-85 USES STD. INPUT IF NO FILE NAME GIVEN
;
; CONVERTED FROM CP/M-80 TO MSDOS, 16-SEP-85
;
; VERSION 1.1: 15-MAR-85
; VERSION 1.0: 15-JAN-85
;
; TO BUILD TAIL.EXE:
; MASM TAIL,TAIL,NUL,NUL
; LINK TAIL,TAIL,NUL,ASM
INBUFSIZE EQU 8192 ;SIZE OF INPUT BUFFER
OUTBUFSIZE EQU 512 ;SIZE OF OUTPUT BUFFER
MAXARGS EQU 40 ;MAX. # COMMAND LINE ARGUMENTS
PRGSIZE EQU 800H ;MAX. SIZE OF PROGRAM + FIXED DATA
.XLIST
INCLUDE ASCII.DEF
INCLUDE MSDOS2.DEF
INCLUDE MACROS.DEF
.LIST
ERROR MACRO ERRNUM ;SHOW ERROR MESSAGE
PUSH DS
MOV AX,DGROUP
MOV DS,AX
MOV DX,OFFSET MSG&ERRNUM
CALL ERRORMSG
POP DS
ENDM
DOSSEG
.MODEL SMALL
; MEMORY DEFINITIONS:
;
.DATA
ENDTXT DW 1 DUP (?) ;OFFSET TO END OF TEXT IN INPUT BUFFER
NREAD DW 1 DUP (?) ;NUMBER OF BYTES READ
SIZEHI DW 1 DUP (?) ;HI WORD OF FILE SIZE
SIZELO DW 1 DUP (?) ;LO WORD OF FILE SIZE
POSHI DW 1 DUP (?) ;HI WORD OF FILE POSITION
POSLO DW 1 DUP (?) ;LO WORD OF FILE POSITION
NUMARGS DW 1 DUP (?) ;NUMBER OF COMMAND LINE ARGUMENTS
INHANDLE DW 0 ;INPUT FILE HANDLE
;(STD. INPUT BY DEFAULT)
NUMLIN DW 20 ;NUMBER OF LINES TO LIST
NUMCNT DW 1 DUP (?) ;COUNTS NUMBER OF LINES TO GO
ONEFILE DB 1 ;FLAG, SET 0 WHEN >1 FILE
ATSTART DB 0 ;FLAG, SET <>0 WHEN AT START OF FILE
AMTTOREAD DW INBUFSIZE ;AMOUNT TO READ ON NEXT READ OP
OUTNDX DW 0 ;INDEX TO NEXT FREE SLOT IN OUTPUT BUFFER
MSG1 DB CR,LF,"tail: can't open: ",0
MSG1E DB CR,LF,0
MSG2 DB CR,LF,"tail: read error.",CR,LF,0
MSG4 DB CR,LF,"tail usage: tail -n file1 file2 ...",CR,LF,0
MSG5 DB CR,LF,"tail: too many command line arguments",CR,LF,0
MSG6 DB CR,LF,"tail: unknown pathname ",0
.STACK
DB 512 DUP (?)
; UNINITIALIZED DATA:
.DATA?
INBUF DB INBUFSIZE DUP (?) ;INPUT BUFFER
OUTBUF DB OUTBUFSIZE DUP (?) ;OUTPUT BUFFER
PREFIX DB 65 DUP (?) ;DRIVE/DIRECTORY PREFIX
SPATH DB 65 DUP (?) ;SEARCH PATH
FILENAME DB 65 DUP (?) ;FILE NAME
ARGPTRS DB (2*MAXARGS) DUP (?) ;POINTERS TO COMMAND LINE ARGUMENTS
ARGBUF DB 300 DUP (?) ;BUFFER FOR COMMAND LINE ARGUMENTS
DTA DB 128 DUP (?) ;DATA TRANSFER AREA FOR DOS
MAXMEM EQU DTA+128
.CODE
EXTRN SKIPSP:NEAR,DTOBIN:NEAR,CPYCNT:NEAR
EXTRN ERRORMSG:NEAR,TYPTX:NEAR,COUT:NEAR
EXTRN FIXPATH:NEAR,GETARGS:NEAR,TYPE_UFN:ABS,TYPE_UNK:ABS
ENTRY:
TEST_DOS2 ;TEST FOR DOS 2.0, EXIT IF DOS 1
MEMOK:
MOV AX,DGROUP
MOV ES,AX ;SET EXTRA SEG TO POINT TO DATA
MOV BX,(80H) ;GET BYTE COUNT FOR COMMAND LINE
CMP BYTE PTR [BX],0 ;TEST IT
JNE L_1 ;IF NOT 0
MOV DS,AX
JMP START ;NO ARGUMENTS, USE STDIN
L_1:
PUSH BX
MOV DL,BYTE PTR [BX]
MOV DH,0
ADD BX,DX
INC BX
MOV BYTE PTR [BX],0 ;PUT 0 BYTE AT END OF COMMAND LINE
POP BX
INC BX ;POINT TO START OF COMMAND LINE
MOV SI,OFFSET ARGPTRS
MOV DI,OFFSET ARGBUF
MOV CX,MAXARGS
CALL GETARGS ;COLLECT COMMAND LINE ARGUMENTS
JNB SHORT L_2 ;IF OK
ERROR 5 ;TOO MANY ARGUMENTS
JMP EXIT2
L_2:
MOV AX,DGROUP
MOV DS,AX ;SET DATA SEG
MOV WORD PTR NUMARGS,CX ;SAVE # OF ARGUMENTS
CMP CX,0
JNE SHORT L_2A ;IF SOME ARGUMENT
JMP START ;NO ARGUMENTS, USE STDIN
L_2A:
MOV SI,OFFSET ARGPTRS
MOV BX,WORD PTR [SI] ;POINT TO 1ST ARGUMENT
MOV AL,BYTE PTR [BX] ;GET 1ST CHAR.
CMP AL,'-'
JE L_3 ;IF SWITCH SPECIFIED
MOV SI,OFFSET ARGPTRS
MOV CX,WORD PTR NUMARGS ;GET # OF ARGUMENTS
JMP GETFILES ;IF NO SWITCH
L_3:
INC BX
MOV CL,0
PUSH BX
CD: MOV AL,BYTE PTR [BX] ;HAVE NUMBER, COUNT NUMBER OF DIGITS
CMP AL,'0'
JC NODGT
CMP AL,'9'+1
JNC NODGT
INC BX
INC CL
JMP SHORT CD
NODGT:
POP BX
MOV CH,0 ;CL HOLDS DIGIT COUNT
CALL DTOBIN ;CONVERT NUMBER TO BINARY
JNC L_4 ;IF OK
JMP SHORT USE
L_4:
CMP AX,0 ;IS NUMBER 0?
JNE NOT0 ;NO.
JMP EXIT2 ;YES, IT IS, JUST EXIT
NOT0:
MOV WORD PTR NUMLIN,AX ;STORE # LINES
MOV SI,OFFSET ARGPTRS+2
MOV CX,WORD PTR NUMARGS ;GET # OF ARGUMENTS
DEC CX ;-1 CAUSE OF SWITCH
JMP SHORT GETFILES
USE:
ERROR 4 ;TELL USER HOW TO USE
JMP EXIT2
START:
CALL TAIL ;SHOW THE "TAIL"
JMP EXIT2
GETFILES:
MOV AX,DGROUP
MOV DS,AX
CMP CX,0 ;NO FILE ARGUMENTS?
JNE GOT1
JMP START ;NO, JUST USE STDIN
GOT1:
CMP CX,1 ;>1 ARG?
JE ONLY1 ;NOPE
MOV BYTE PTR ONEFILE,0 ;>1 ARG
ONLY1:
ARGLUP: MOV BX,WORD PTR [SI] ;BX POINTS TO FILE NAME
PUSH CX
PUSH SI
CALL DOARG
POP SI
POP CX
SKIPSW:
ADD SI,2
LOOP ARGLUP
JMP EXIT2
; DOARG = PROCESS 1 ARGUMENT
; ES:BX POINTS TO IT
DOARG PROC NEAR
MOV AH,SET_DTA
MOV DX,OFFSET DTA
INT DOS ;SET DTA
MOV CX,OFFSET SPATH
MOV DX,OFFSET PREFIX
PUSH BX
CALL FIXPATH ;PARSE PATHNAME
POP BX
CMP AL,TYPE_UNK
JE BADNAME
CMP AL,TYPE_UFN
JE GOTNAME ;IF UNAMBIG. FILE NAME
MOV BYTE PTR ONEFILE,0 ;AMBIG. FILE NAME OR DIR, FLAG IT
JMP SHORT GOTNAME
BADNAME:
MOV DX,OFFSET MSG6
CALL ERRORMSG ;BAD FILE NAME, SHOW MSG.
MOV DX,BX
CALL ERRORMSG ;SHOW FILE THAT CAUSED IT
RET
GOTNAME:
MOV DX,OFFSET SPATH ;POINT TO SEARCH PATH
MOV CX,31H ;SET SEARCH ATTRIBUTES
MOV AH,FIND_FIRST
INT DOS ;SEARCH FOR 1ST MATCH
JB BADNAME ;IF NOTHING FOUND
GOTFILE:
MOV SI,OFFSET PREFIX
MOV DI,OFFSET FILENAME
MOV CX,65
CALL CPYCNT ;COPY PREFIX TO FILE NAME AREA
DEC DI ;BACK UP OVER NULL
MOV SI,(OFFSET DTA)+30 ;POINT TO FILE NAME WE FOUND
CMP [SI],BYTE PTR '.' ;DOES IT START WITH .? -
JNE NOTDOT ;- NO
JMP SHORT SKIPFILE ;YES, JUST SKIP IT
NOTDOT:
CALL CPYCNT ;COPY FILE WE FOUND AFTER PREFIX
CALL DOFILE ;DO 1 FILE
SKIPFILE:
MOV AH,FIND_NEXT
INT DOS ;FIND NEXT MATCH, IF ANY
JC NOMORE ;IF NONE
JMP GOTFILE ;GOT ONE, BACK TO TOP OF LOOP
NOMORE:
RET
DOARG ENDP
DOFILE PROC NEAR
MOV DX,OFFSET FILENAME ;DX POINTS TO FILE NAME
MOV AL,READ_ACCESS
MOV AH,DOS2_OPEN
INT DOS ;TRY TO OPEN FILE
JB BADOPN ;IF ERROR
MOV WORD PTR INHANDLE,AX ;SAVE FILE HANDLE
CMP BYTE PTR ONEFILE,1 ;ONE FILE ONLY?
JE NOSHOW ;YES, DON'T SHOW NAME
CALL SHOWFILE ;SHOW FILE NAME
NOSHOW:
CALL TAIL ;SHOW TAIL OF FILE
RET
BADOPN:
MOV DX,OFFSET MSG1
CALL ERRORMSG ;CAN'T OPEN FILE
MOV DX,OFFSET FILENAME
CALL ERRORMSG ;SHOW NAME
MOV DX,OFFSET MSG1E
CALL ERRORMSG ;SHOW CR/LF
RET
DOFILE ENDP
; SHOW FILE NAME
SHOWFILE PROC NEAR
MOV AX,"="
MOV CX,5
BARS:
CALL WRITEBYTE
LOOP BARS
MOV AX,SPACE
CALL WRITEBYTE
MOV BX,OFFSET FILENAME
SHOWF: MOV AL,BYTE PTR [BX]
CMP AL,0
JE ENDF
CALL WRITEBYTE
INC BX
JMP SHOWF
ENDF: MOV AL,SPACE
CALL WRITEBYTE
MOV AL,'='
MOV CX,5
BARS2:
CALL WRITEBYTE
LOOP BARS2
MOV AL,CR
CALL WRITEBYTE
MOV AL,LF
CALL WRITEBYTE
RET
SHOWFILE ENDP
; AFTER A FILE HAS BEEN OPENED, THIS PROCEDURE OUTPUTS ITS "TAIL"
TAIL PROC NEAR
MOV BYTE PTR ATSTART,0 ;CLEAR "AT START" FLAG
MOV WORD PTR AMTTOREAD,INBUFSIZE ;SET INITIAL AMOUNT TO READ
MOV AX,WORD PTR NUMLIN ;GET # LINES TO SHOW
MOV WORD PTR NUMCNT,AX ;INIT COUNT
MOV BX,WORD PTR INHANDLE ;GET FILE HANDLE
MOV DX,0
MOV CX,0
MOV AL,2
MOV AH,LSEEK
INT DOS ;SEEK TO END OF FILE
MOV WORD PTR SIZEHI,DX
MOV WORD PTR SIZELO,AX ;SAVE FILE SIZE
CMP DX,0
JNE BIG ;IF HI WORD >0
CMP AX,0
JNE L_11
JMP CLOSEFILE ;IF FILE SIZE 0, JUST EXIT
L_11:
CMP AX,INBUFSIZE
JC SMALL ;IF FILE SIZE < BUFFER SIZE
BIG:
SUB AX,INBUFSIZE
JNB NOBORROW
DEC DX
NOBORROW:
MOV CX,DX ;CX = MSW OF OFFSET
MOV DX,AX ;DX = LSW OF OFFSET
MOV BX,WORD PTR INHANDLE
MOV AL,0
MOV AH,LSEEK
INT DOS ;MOVE FILE POINTER BACK BY BUFSIZ
MOV WORD PTR POSHI,DX ;SAVE HI WORD OF POSITION
MOV WORD PTR POSLO,AX ;SAVE LO WORD OF POSITION
JMP FILLBUF
SMALL:
MOV CX,0
MOV DX,0
MOV AL,0
MOV BX,WORD PTR INHANDLE
MOV AH,LSEEK
INT DOS ;REWIND TO START OF FILE
MOV BYTE PTR ATSTART,1 ;SET "AT START" FLAG
FILLBUF:
MOV CX,WORD PTR AMTTOREAD ;CX = # BYTES TO READ
MOV BX,WORD PTR INHANDLE ;BX = FILE HANDLE
MOV DX,OFFSET INBUF ;OFFSET TO BUFFER
MOV AH,READ
INT DOS ;FILL BUFFER FROM FILE
JNB READOK ;IF NO ERROR
JMP BADREAD ;IF READ ERROR
READOK:
MOV WORD PTR NREAD,AX ;SAVE # BYTES READ
MOV CX,AX
MOV BX,OFFSET INBUF
SRCEND:
MOV AL,BYTE PTR [BX]
CMP AL,CTRL$Z
JE FOUND ;IF ^Z FOUND
INC BX
LOOP SRCEND
FOUND:
MOV WORD PTR ENDTXT,BX ;SAVE ADDRESS OF END OF TEXT
;(ACTUALLY, OFFSET FR. DATA SEGMENT)
JMP SHORT SRC1
SRC: DEC BX
SRC1:
CMP BX,OFFSET INBUF ;AT START OF BUFFER?
JE NEWBUF ;YES, BACK UP FURTHER (IF POSSIBLE)
MOV AL,BYTE PTR [BX] ;GET BYTE
CMP AL,CR ;IF NOT CR,
JNE SRC ;LOOP
MOV AX,1 ;FOUND CR,
SUB WORD PTR NUMCNT,AX ;COUNT 1 LINE
JNB SRC ;LOOP IF COUNT STILL >0
ADD BX,2 ;START OF RIGHT LINE FOUND, SKIP CR/LF
JMP BEGIN ;BEGIN OUTPUT
NEWBUF: CMP BYTE PTR ATSTART,0 ;SEE IF WE CAN BACK UP MORE
JNE BEGIN ;NO, WE CAN'T
MOV AX,WORD PTR POSLO ;GET LO WORD OF FILE POSITION
SUB AX,INBUFSIZE ;SUBTRACT BUFFER SIZE
MOV BX,WORD PTR POSHI ;GET HI WORD OF FILE POSITION
SBB BX,0 ;IF 'C' FLAG SET, SUBTRACT 1
JB TOOFAR ;IF <1 BUFFER LEFT TO GO
MOV CX,BX
MOV DX,AX ;OFFSET IN CX:DX
MOV BX,WORD PTR INHANDLE
MOV AL,0
MOV AH,LSEEK
INT DOS ;MOVE FILE POINTER BACK
MOV WORD PTR POSHI,DX
MOV WORD PTR POSLO,AX ;SAVE NEW POSITION
JMP FILLBUF ;GO FILL BUFFER AGAIN
; COME HERE WHEN <1 FULL BUFFER REMAINS TO BE READ
TOOFAR: MOV AX,WORD PTR POSLO
MOV WORD PTR AMTTOREAD,AX ;SET AMT TO READ = AMOUNT UNREAD
MOV CX,0
MOV DX,0 ;MOVE TO START OF FILE
MOV BX,WORD PTR INHANDLE
MOV AL,0
MOV AH,LSEEK
INT DOS ;SEEK TO START
MOV BYTE PTR ATSTART,1 ;SET "AT START" FLAG
JMP FILLBUF ;GO FILL BUFFER
; READY TO OUTPUT LINE(S)
BEGIN:
MOV DX,WORD PTR ENDTXT ;GET END OF TEXT IN DX
SHOW: CMP DX,BX ;DISPLAY TEXT - TOP OF LOOP
JE ENDBUF ;UNTIL END OF BUFFER
MOV AL,BYTE PTR [BX]
CALL WRITEBYTE
CMP AL,CTRL$Z ;QUIT IF ^Z WRITTEN
JE DONE
INC BX
JMP SHOW
ENDBUF:
MOV CX,INBUFSIZE ;CX = # BYTES TO READ
MOV BX,WORD PTR INHANDLE ;BX = FILE HANDLE
MOV DX,0 ;OFFSET TO BUFFER FROM ES
MOV AH,READ
INT DOS ;FILL BUFFER FROM FILE
JB BADREAD ;IF ERROR
MOV DX,AX ;SAVE BYTES READ
CMP AX,0
JE DONE ;DONE IF 0
MOV BX,0 ;BX = OFFSET TO START OF BUFFER
JMP SHOW ;OUTPUT SOME MORE
BADREAD:
MOV DX,OFFSET MSG2
CALL ERRORMSG
DONE:
CLOSEFILE:
MOV BX,WORD PTR INHANDLE
MOV AH,DOS2_CLOSE
INT DOS ;CLOSE FILE
CALL FLUSH ;FLUSH ANYTHING IN OUTPUT BUFFER
RET
TAIL ENDP
EXIT2:
MOV AH,EXIT
INT DOS ;EXIT TO DOS
; WRITE A BYTE TO THE OUTPUT
;
WRITEBYTE PROC NEAR
PUSH BX
PUSH CX
PUSH DX
MOV BX,WORD PTR OUTNDX
MOV BYTE PTR [BX+OUTBUF],AL
INC BX
MOV WORD PTR OUTNDX,BX
CMP BX,OUTBUFSIZE
JL NOTFUL
CALL FLUSH
NOTFUL:
POP DX
POP CX
POP BX
RET
WRITEBYTE ENDP
; FLUSH - WRITE OUTPUT BUFFER
FLUSH PROC NEAR
PUSH AX
MOV CX,WORD PTR OUTNDX
MOV DX,OFFSET OUTBUF
MOV BX,1
MOV AH,WRITE
INT DOS ;WRITE TO OUTPUT
POP AX
MOV WORD PTR OUTNDX,0
RET
FLUSH ENDP
END ENTRY